
#define _CRT_SECURE_NO_DEPRECATE
#define _CRT_SECURE_NO_WARNINGS

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>

#ifdef   _MSC_VER
typedef unsigned __int64 uint64_t;
#else
#include <inttypes.h>
#endif

//#define   RANDOM_BP_TESTING
//#define   TICKER

const int p3[6][3] = { { 0,1,2 }, { 0,2,1 }, { 1,0,2 }, { 1,2,0 }, { 2,0,1 }, { 2,1,0 } };

int first_bit[512];
int box_table[9][9];

void setup_tables(){
     for (int i = 1; i < 512; i++) {
         int mask = i;
         int bit = 0;
         while (!(mask & 1)) {
            ++bit;
            mask >>= 1;
         }
         first_bit[i] = bit;
      }
 
      for (int i = 0; i < 9; i++)
      for (int j = 0; j < 9; j++)
         box_table[i][j] = 3 * (i / 3) + (j / 3);
}

#ifdef   RANDOM_BP_TESTING

unsigned int rng_state[16] = {
   // fixed seed
   0xf3ac2ba5u, 0xbf0c8a61u, 0x6655c7b8u, 0x95203b06u,
   0xe0fe5cb2u, 0xfa36a3cau, 0x2b1eceddu, 0xab881428u,
   0x0cd61f0au, 0xa6ce97fau, 0xabafe960u, 0xd410f1d6u,
   0x04986890u, 0xe59876c9u, 0xe9c4491au, 0x8287866fu,
};

int rng_index;

unsigned int urand32()
{
   unsigned int a = rng_state[rng_index];
   unsigned int c = rng_state[(rng_index + 13) & 15];
   unsigned int b = a ^ c ^ (a << 16) ^ (c << 15);

   c = rng_state[(rng_index + 9) & 15];
   c ^= (c >> 11);
   a = rng_state[rng_index] = b ^ c;

   unsigned int d = a ^ ((a << 5) & 0xda442d24u);

   rng_index = (rng_index + 15) & 15;

   a = rng_state[rng_index];
   rng_state[rng_index] = a ^ b ^ d ^ (a << 2) ^ (b << 18) ^ (c << 28);

   return rng_state[rng_index];
}
#endif

const char *gtypes[44] = {
   "123456789123456789123456789",
   "123456789123456789123457689",
   "123456789123456789124357689",
   "123456789123456789124378569",
   "123456789123456789147258369",
   "123456789123457689123458679",
   "123456789123457689123468579",
   "123456789123457689124356789",
   "123456789123457689124358679",
   "123456789123457689124367589",
   "123456789123457689124368579",
   "123456789123457689124389567",
   "123456789123457689126345789",
   "123456789123457689126347589",
   "123456789123457689126348579",
   "123456789123457689145267389",
   "123456789123457689145268379",
   "123456789123457689146258379",
   "123456789123457689148259367",
   "123456789124357689125348679",
   "123456789124357689125367489",
   "123456789124357689125368479",
   "123456789124357689125378469",
   "123456789124357689126358479",
   "123456789124357689126378459",
   "123456789124357689126389457",
   "123456789124357689128345679",
   "123456789124357689128356479",
   "123456789124357689128359467",
   "123456789124357689134258679",
   "123456789124357689134268579",
   "123456789124357689135268479",
   "123456789124357689135278469",
   "123456789124357689136258479",
   "123456789124357689136278459",
   "123456789124357689137268459",
   "123456789124357689138259467",
   "123456789124357689138269457",
   "123456789124357689158267349",
   "123456789124378569129356478",
   "123456789124378569135279468",
   "123456789124378569137245689",
   "123456789124378569157268349",
   "123456789147258369159267348",
};

const char *ggrids[44] = {
   "147258369258369147369147258471582693683491725592673481714925836936814572825736914",
   "147268359258349176369157248481592763673481925592673481814925637736814592925736814",
   "147368259269157438358249176471582963685493712923716845734925681812634597596871324",
   "147359286258167439369248175481932657673485912925716348794523861812674593536891724",
   "148269753259347186367158429471692835592483617683715942724836591916524378835971264",
   "147256389258379146369148257471562893693481725582793461714625938835914672926837514",
   "147256389258349167369178245471562893593481726682793451714625938835914672926837514",
   "147358269259176438368249157431682975875493612926715843694527381512834796783961524",
   "147356289258179436369248157471832965683495712925617348894523671512764893736981524",
   "147358269259176438368249175481762953695483712723915846934527681812634597576891324",
   "147356289268179435359248167471832956683495712925617348894523671512764893736981524",
   "147358296268179435359246187481792653675483912923615748834927561512864379796531824",
   "147258639259376148368149257471562893693481725582793461914825376735614982826937514",
   "147258639259346178368179245481962753573481926692537481814623597935714862726895314",
   "147258639259346187368179245471562893593481726682793451714925368835614972926837514",
   "148279563259346178367158429471682935982435617536917842624593781715824396893761254",
   "148279563257346189369158427471692835536487912982513746724835691615924378893761254",
   "147259683269348157358176429481762935592483716673915248824597361715634892936821574",
   "147256893268349157359178426431982675572463918896715342624897531715634289983521764",
   "147236589258479136369158247471923865625841973983765412534612798796584321812397654",
   "147238569259476138368159274471623985685941327932785416714562893896314752523897641",
   "147236589268459137359178264481623975675941328932785416714562893896314752523897641",
   "147236589258479136369158274471923865685741923932685417514362798793814652826597341",
   "147238659268459137359176284481623975675941328932785416714562893593814762826397541",
   "147239685258476139369158274471823956695741328832965417714592863583614792926387541",
   "147238695268459137359176284481923576675841329932765418714592863893614752526387941",
   "147236859258479136369158247471923685625841793983765412534612978796384521812597364",
   "147236859268459137359178264481623795675941328932785416714562983593814672826397541",
   "147239856269458137358176294481923765675841329932765418714592683893614572526387941",
   "147256389268139457359478126481723695695841732723965841814692573572314968936587214",
   "147256389258139467369478125481723956695841732723965841814692573572314698936587214",
   "147236589258179364369458127481923756572641938693785412714562893936814275825397641",
   "147236589268159374359478126481623957572941638693785412714362895925814763836597241",
   "147238659259176384368459127481923576625741938793685412514862793972314865836597241",
   "147239685269158374358476129481923567625741938793685412814562793972314856536897241",
   "147256389258139764369478125481923576625741938793685412514362897972814653836597241",
   "147239856258176394369458127471923568582641739693785412714362985925814673836597241",
   "147236895258179364369458127481623579675941238923785416714562983896314752532897641",
   "147238569268459173359176824471923685685741392932865417814592736723614958596387241",
   "147235968259486137368179254471523689695841723832967415514392876783614592926758341",
   "147236598269185374358479126471823965625941837893567412714352689982614753536798241",
   "147286359258139746369475128471923685625841973983567412534612897896754231712398564",
   "147236589258479163369185724471523698695841237832967415514392876783614952926758341",
   "148729563269453178357186924471832659592641387836975412714368295985214736623597841",
};

struct gangster_data {
   int first_n_aut;
   int n_aut_count;   // 1st is identity map
   int first_g_aut;
   int g_aut_count;   // 1st is identity transformation
};

gangster_data gtd[44];

int g_aut_c_order[392][9];
unsigned char g_aut_maps[392][10];
unsigned char n_aut_maps[355][10];

void setup44()
{
   int next_g_aut = 0;
   int next_n_aut = 0;

   for (int n44 = 0; n44 < 44; n44++)
   {
      unsigned char band_data[9][3];
      {
         for (int i = 0; i < 9; i++)
         for (int j = 0; j < 3; j++)
            band_data[i][j] = gtypes[n44][3 * i + j] - '0';
      }

      gtd[n44].first_n_aut = next_n_aut;

      {
         int aut_count = 0;   // numeric only

         int col_p[3];
         for (col_p[0] = 0; col_p[0] < 6; col_p[0]++)
         for (col_p[1] = 0; col_p[1] < 6; col_p[1]++)
         for (col_p[2] = 0; col_p[2] < 6; col_p[2]++)
         {
            unsigned char map[10];
            map[0] = 0;
            {
               for (int i = 0; i < 3; i++)
               for (int j = 0; j < 3; j++)
                  map[band_data[i][j]] = band_data[i][p3[col_p[i]][j]];
            }
            bool ok = true;
             for (int i = 0; i < 9; i++)
            {
               unsigned char n0 = map[band_data[i][0]];
               unsigned char n1 = map[band_data[i][1]];
               unsigned char n2 = map[band_data[i][2]];
               if (n0 > n1) {
                  unsigned char n = n0;
                  n0 = n1;
                  n1 = n;
               }
               if (n0 > n2) {
                  unsigned char n = n0;
                  n0 = n2;
                  n2 = n;
               }
               if (n0 != band_data[i][0])
               {
                  ok = false;
                  break;
               }
               if (n1 > n2) {
                  unsigned char n = n1;
                  n1 = n2;
                  n2 = n;
               }
               if (n1 != band_data[i][1])
               {
                  ok = false;
                  break;
               }
               if (n2 != band_data[i][2])
               {
                  ok = false;
                  break;
               }
            }
            if (ok)
            {
               ++aut_count;
               memcpy(n_aut_maps[next_n_aut++], map, 10);
            }
         }

         gtd[n44].n_aut_count = aut_count;
      }

      gtd[n44].first_g_aut = next_g_aut;

      {
         int aut_count = 0;   // geometric + (one) numeric

         unsigned char map[10];
         map[0] = 0;

         int row_p[3];
         for (int band_p = 0; band_p < 6; band_p++)
         for (row_p[0] = 0; row_p[0] < 6; row_p[0]++)
         for (row_p[1] = 0; row_p[1] < 6; row_p[1]++)
         for (row_p[2] = 0; row_p[2] < 6; row_p[2]++)
         {
            int r_order[9];
            {
               for (int i = 0; i < 3; i++)
               for (int j = 0; j < 3; j++)
                  r_order[3 * i + j] = 3 * p3[band_p][i] + p3[row_p[i]][j];
            }

            bool found = false;

            int col_p[3];
            for (col_p[0] = 0; col_p[0] < 6; col_p[0]++)
            for (col_p[1] = 0; col_p[1] < 6; col_p[1]++)
            for (col_p[2] = 0; col_p[2] < 6; col_p[2]++)
            {
               {
                  for (int i = 0; i < 3; i++)
                  for (int j = 0; j < 3; j++)
                     map[band_data[r_order[i]][j]] = band_data[i][p3[col_p[i]][j]];
               }
               bool ok = true;
                for (int i = 0; i < 9; i++)
               {
                  unsigned char n0 = map[band_data[r_order[i]][0]];
                  unsigned char n1 = map[band_data[r_order[i]][1]];
                  unsigned char n2 = map[band_data[r_order[i]][2]];
                  if (n0 > n1) {
                     unsigned char n = n0;
                     n0 = n1;
                     n1 = n;
                  }
                  if (n0 > n2) {
                     unsigned char n = n0;
                     n0 = n2;
                     n2 = n;
                  }
                  if (n0 != band_data[i][0])
                  {
                     ok = false;
                     break;
                  }
                  if (n1 > n2) {
                     unsigned char n = n1;
                     n1 = n2;
                     n2 = n;
                  }
                  if (n1 != band_data[i][1])
                  {
                     ok = false;
                     break;
                  }
                  if (n2 != band_data[i][2])
                  {
                     ok = false;
                     break;
                  }
               }
               if (ok)
               {
                  found = true;
                  goto found;
               }
            }

found:         if (found)
            {
               ++aut_count;
               memcpy(g_aut_maps[next_g_aut], map, 10);
               memcpy(g_aut_c_order[next_g_aut++], r_order, sizeof(r_order));
            }
         }

         gtd[n44].g_aut_count = aut_count;
      }
   }
}


#ifdef   _MSC_VER
__int64 puzzle_count;
#else
uint64_t puzzle_count;
#endif

void bp_handler(char *buf, int n44 = -1)
{
   // generate puzzles to be tested for input <band,pattern> case

   if (n44 < 0)
   {
      for (n44 = 0; n44 < 44; n44++)
      {
         if (!strncmp(buf, ggrids[n44], 27))
            break;
      }

      if (n44 >= 44)
      {
         puts("bug");
         exit(-1);
      }
   }

   gangster_data &gt = gtd[n44];

   struct _grid {
      unsigned char cells[9][9];
      int boxmasks[9];
      int rowmasks[9];
      int colmasks[9];
   };

   _grid grid;
   memset(&grid, 0, sizeof(grid));

   {
      for (int i = 0; i < 27; i++)
      {
         grid.cells[i / 9][i % 9] = buf[i] - '0';
         grid.colmasks[i % 9] |= (1 << (buf[i] - '0'));
      }
   }

   enum { MaxPatCells = 8, };

   int numbers[MaxPatCells];

   struct spot {
      int r;
      int c;
      int b;
      int dmask;
   };

   spot spots[MaxPatCells];

   spot *s = spots;

   {
      for (int i = 27; i < 81; i++)
      {
         if (buf[i] < '0' || buf[i] > '9')
            continue;

         if (s >= spots + MaxPatCells)
         {
            puts("MaxPatCells exceeded");
            exit(-1);
         }

         s->r = i / 9;
         s->c = i % 9;
         s->b = box_table[s->r][s->c];
         ++s;
      }
   }

   int pat_cells = (int)(s - spots);

   s = spots;

next_spot:

   {
      int mask = grid.rowmasks[s->r]
         | grid.colmasks[s->c]
         | grid.boxmasks[s->b];

      mask = 511 & ~(mask >> 1);
      if (!mask)
         goto backtrack;

      s->dmask = mask;
   }

next_value:

   {
      int number = first_bit[s->dmask] + 1;
      s->dmask &= (s->dmask - 1);

      numbers[s - spots] = number;

      grid.cells[s->r][s->c] = number;
      grid.rowmasks[s->r] |= (1 << number);
      grid.colmasks[s->c] |= (1 << number);
      grid.boxmasks[s->b] |= (1 << number);
   }

   if (++s < spots + pat_cells)
      goto next_spot;

   {
      // skip puzzle if it is "gangster equivalent" (via relabeling),
      // to a puzzle that has already been checked.

      unsigned char *map = n_aut_maps[gt.first_n_aut] + 10;

      for (int n = 1; n < gt.n_aut_count; n++)
      {
         for (int i = 0; i < pat_cells; i++)
         {
            int d = map[numbers[i]];
            if (d < numbers[i])
               goto backtrack;
            if (d > numbers[i])
               break;
         }

         map += 10;
      }
   }

   // TODO:: dump or test puzzle in 'grid.cells[][]'

   ++puzzle_count;

backtrack:

   if (--s < spots)
      return;

   {
      int number = grid.cells[s->r][s->c];

      grid.cells[s->r][s->c] = 0;
      grid.rowmasks[s->r] &= ~(1 << number);
      grid.colmasks[s->c] &= ~(1 << number);
      grid.boxmasks[s->b] &= ~(1 << number);
   }

   if (!s->dmask)
      goto backtrack;

   goto next_value;
}

int patterns[1296][2];
int pattern_count;
bool p_flags[1296];

int p_compare(const void *p1, const void *p2)
{
   int res = ((const int *)p2)[0] - ((const int *)p1)[0];
   if (!res)
      res = ((const int *)p2)[1] - ((const int *)p1)[1];
   return res;
}

int find_pattern(int n1, int n2)
{
   int start = -1;
   int end = pattern_count;

   while (end > start + 1)
   {
      int n = (start + end) >> 1;

      int res = patterns[n][0] - n1;
      if (!res)
         res = patterns[n][1] - n2;

      if (!res)
         return n;

      if (res < 0)
         end = n;
      else
         start = n;
   }

   return -1;
}


#define SortBand23ToMaxlex \
if (m[0] < m[1]) { int n = m[0]; m[0] = m[1]; m[1] = n; }\
if (m[0] < m[2]) { int n = m[0]; m[0] = m[2]; m[2] = n; }\
if (m[1] < m[2]) { int n = m[1]; m[1] = m[2]; m[2] = n; }\
if (m[3] < m[4]) { int n = m[3]; m[3] = m[4]; m[4] = n; }\
if (m[3] < m[5]) { int n = m[3]; m[3] = m[5]; m[5] = n; }\
if (m[4] < m[5]) { int n = m[4]; m[4] = m[5]; m[5] = n; }\
int n1 = (m[0] << 18) | (m[1] << 9) | m[2];\
int n2 = (m[3] << 18) | (m[4] << 9) | m[5];\
if (band_swap && n1 < n2) { int n = n1; n1 = n2; n2 = n; }

int mainblue(int argc, char **argv){
#ifdef   RANDOM_BP_TESTING
   if (argc != 3)
   {
      puts("usage: t3544 <first> <count> ... 0-16383 range");
      exit(0);
   }

   int start = atoi(argv[1]);
   int end = start + atoi(argv[2]);
#endif

   setup_tables();
   setup44();

   FILE *fp = fopen("ed3544.txt", "r");

   if (!fp)
   {
      puts("input file");
      exit(-1);
   }

   char buf[256];

   int bp_count = 0;

#ifdef   TICKER
   int index = 0;
#endif

   while (fgets(buf, 256, fp))
   {
      if (strlen(buf) < 81
      || buf[0] != '0' && buf[0] != '1')
         continue;

#ifdef   TICKER
      fprintf(stderr, "%05d", ++index);
#endif

      unsigned char grid[81];

      int counts[3];
      counts[0] = 0;
      counts[1] = 0;
      counts[2] = 0;

      {
         for (int i = 0; i < 81; i++)
         {
            grid[i] = buf[i] - '0';
            if (grid[i])
               ++counts[i / 27];
         }

         if (counts[0] != 27)
         {
            puts("unexpected pattern layout");
            exit(-1);
         }
      }

      bool band_swap = (counts[1] == counts[2]);

      // 'grid' contains one of the ED 27+?+? patterns

      {
         // generate patterns produced by start & column permutations

         int np = 0;

         int col_p[3];
         for (int stack_p = 0; stack_p < 6; stack_p++)
         for (col_p[0] = 0; col_p[0] < 6; col_p[0]++)
         for (col_p[1] = 0; col_p[1] < 6; col_p[1]++)
         for (col_p[2] = 0; col_p[2] < 6; col_p[2]++)
         {
            int m[6];
            memset(m, 0, sizeof(m));

            {
               int c_order[9];

               {
                  for (int i = 0; i < 3; i++)
                  for (int j = 0; j < 3; j++)
                     c_order[3 * i + j] = 3 * p3[stack_p][i] + p3[col_p[i]][j];
               }

               for (int i = 0; i < 6; i++)
               for (int j = 0; j < 9; j++)
               {
                  if (grid[27 + 9 * i + c_order[j]])
                     m[i] |= 0x100 >> j;
               }
            }
			SortBand23ToMaxlex;
/*
            if (m[0] < m[1]) { int n = m[0]; m[0] = m[1]; m[1] = n; }
            if (m[0] < m[2]) { int n = m[0]; m[0] = m[2]; m[2] = n; }
            if (m[1] < m[2]) { int n = m[1]; m[1] = m[2]; m[2] = n; }

            if (m[3] < m[4]) { int n = m[3]; m[3] = m[4]; m[4] = n; }
            if (m[3] < m[5]) { int n = m[3]; m[3] = m[5]; m[5] = n; }
            if (m[4] < m[5]) { int n = m[4]; m[4] = m[5]; m[5] = n; }

            int n1 = (m[0] << 18) | (m[1] << 9) | m[2];
            int n2 = (m[3] << 18) | (m[4] << 9) | m[5];

            if (band_swap && n1 < n2) { int n = n1; n1 = n2; n2 = n; }
*/
            patterns[np][0] = n1;
            patterns[np][1] = n2;
            ++np;
         }
      }

      {
         // remove duplicates

         qsort(patterns, 1296, sizeof(patterns[0]), p_compare);
         pattern_count = 1;

         for (int np = 1; np < 1296; np++)
         {
            if (patterns[np][0] != patterns[pattern_count - 1][0]
            || patterns[np][1] != patterns[pattern_count - 1][1])
            {
               patterns[pattern_count][0] = patterns[np][0];
               patterns[pattern_count][1] = patterns[np][1];
               ++pattern_count;
            }
         }
      }

      // loop over gangster classes producing <band,pattern> cases
      //  that need be tested ...

      for (int n44 = 0; n44 < 44; n44++)
      {
         memset(p_flags, 0, pattern_count * sizeof(p_flags[0]));

         for (int np = 0; np < pattern_count; np++)
         {
            if (p_flags[np])
               continue;

            // will need to test pattern 'np' with (gangster) band 'n44'

            int m0[6];
            m0[0] = (patterns[np][0] >> 18) & 511;
            m0[1] = (patterns[np][0] >> 9) & 511;
            m0[2] = patterns[np][0] & 511;
            m0[3] = (patterns[np][1] >> 18) & 511;
            m0[4] = (patterns[np][1] >> 9) & 511;
            m0[5] = patterns[np][1] & 511;

#ifdef   RANDOM_BP_TESTING
            {
               int r = urand32() >> (32 - 4);
               r = (r << 5) | (urand32() >> (32 - 5));
               r = (r << 5) | (urand32() >> (32 - 5));   // 16384 possible results

               if (r >= start && r < end)
               {
                  for (int i = 0; i < 9; i++)
                  for (int j = 0; j < 9; j++)
                     buf[9 * i + j] = (i < 3 || (m0[i - 3] & (0x100 >> j)))
                        ? ggrids[n44][9 * i + j] : '.';

                  buf[81] = 0;
                  bp_handler(buf, n44);   // handle <band,pattern> case

                  ++bp_count;
               }
            }
#else
            {
               for (int i = 0; i < 9; i++)
               for (int j = 0; j < 9; j++)
                  buf[9 * i + j] = (i < 3 || (m0[i - 3] & (0x100 >> j)))
                     ? ggrids[n44][9 * i + j] : '.';

               buf[81] = 0;
               bp_handler(buf, n44);   // handle <band,pattern> case

               ++bp_count;
            }
#endif

            // mark equivalent <band,pattern> cases as "handled"

            gangster_data &gt = gtd[n44];

            int *c_order = g_aut_c_order[gt.first_g_aut] + 9;

            for (int k = 1; k < gt.g_aut_count; k++)
            {
               int m[6];
               memset(m, 0, sizeof(m));

               for (int i = 0; i < 6; i++)
               for (int j = 0; j < 9; j++)
               {
                  if (m0[i] & (0x100 >> c_order[j]))
                     m[i] |= 0x100 >> j;
               }

               if (m[0] < m[1]) { int n = m[0]; m[0] = m[1]; m[1] = n; }
               if (m[0] < m[2]) { int n = m[0]; m[0] = m[2]; m[2] = n; }
               if (m[1] < m[2]) { int n = m[1]; m[1] = m[2]; m[2] = n; }

               if (m[3] < m[4]) { int n = m[3]; m[3] = m[4]; m[4] = n; }
               if (m[3] < m[5]) { int n = m[3]; m[3] = m[5]; m[5] = n; }
               if (m[4] < m[5]) { int n = m[4]; m[4] = m[5]; m[5] = n; }

               int n1 = (m[0] << 18) | (m[1] << 9) | m[2];
               int n2 = (m[3] << 18) | (m[4] << 9) | m[5];

               if (band_swap && n1 < n2) { int n = n1; n1 = n2; n2 = n; }

               p_flags[find_pattern(n1, n2)] = true;

               c_order += 9;
            }
         }
      }

#ifdef   TICKER
      fprintf(stderr, "%c%c%c%c%c", 8, 8, 8, 8, 8);
#endif

      // read next ED 27+?+? pattern
   }

   fprintf(stderr, "<band,pattern> count = %d\n", bp_count);
#ifdef   _MSC_VER
//   fprintf(stderr, "puzzle_count = %I64d [%d-%d], %.2fm\n",
//      puzzle_count, start, end - 1, (double)clock() / CLOCKS_PER_SEC / 60);
#else
   fprintf(stderr, "puzzle_count = %lld [%d-%d], %.2fm\n",
      puzzle_count, start, end - 1, (double)clock() / CLOCKS_PER_SEC / 60);
#endif

   return 0;
}


/*

int mainblue(int argc, char **argv){
   setup_tables();   setup44();

   FILE *fp = fopen("ed3544.txt", "r");
   if (!fp)   {  puts("input file");   exit(-1);   }

   char buf[256];
   int bp_count = 0;

   while (fgets(buf, 256, fp))   {
      if (strlen(buf) < 81  || buf[0] != '0' && buf[0] != '1')   continue;
      unsigned char grid[81];
      int counts[3]={0,0,0};    
	  for (int i = 0; i < 81; i++)   {
            grid[i] = buf[i] - '0';
            if (grid[i])   ++counts[i / 27];
         }
      if (counts[0] != 27)  {
            puts("unexpected pattern layout");
            exit(-1);
         } 
      bool band_swap = (counts[1] == counts[2]);

      // 'grid' contains one of the ED 27+?+? patterns

      {  // generate patterns produced by start & column permutations

       }

      // loop over gangster classes producing <band,pattern> cases
      //  that need be tested ...

      for (int n44 = 0; n44 < 44; n44++)      {
         memset(p_flags, 0, pattern_count * sizeof(p_flags[0]));
         for (int np = 0; np < pattern_count; np++)         {
            if (p_flags[np])               continue;
            // will need to test pattern 'np' with (gangster) band 'n44'
            int m0[6];
            m0[0] = (patterns[np][0] >> 18) & 511;
            m0[1] = (patterns[np][0] >> 9) & 511;
            m0[2] = patterns[np][0] & 511;
            m0[3] = (patterns[np][1] >> 18) & 511;
            m0[4] = (patterns[np][1] >> 9) & 511;
            m0[5] = patterns[np][1] & 511;
            {
               for (int i = 0; i < 9; i++)
               for (int j = 0; j < 9; j++)
                  buf[9 * i + j] = (i < 3 || (m0[i - 3] & (0x100 >> j)))
                     ? ggrids[n44][9 * i + j] : '.';

               buf[81] = 0;
               bp_handler(buf, n44);   // handle <band,pattern> case

               ++bp_count;
            }

            // mark equivalent <band,pattern> cases as "handled"
            gangster_data &gt = gtd[n44];
            int *c_order = g_aut_c_order[gt.first_g_aut] + 9;

            for (int k = 1; k < gt.g_aut_count; k++)      {
               int m[6];
               memset(m, 0, sizeof(m));

               for (int i = 0; i < 6; i++)
               for (int j = 0; j < 9; j++)  {
                  if (m0[i] & (0x100 >> c_order[j]))
                     m[i] |= 0x100 >> j;
               }

               if (m[0] < m[1]) { int n = m[0]; m[0] = m[1]; m[1] = n; }
               if (m[0] < m[2]) { int n = m[0]; m[0] = m[2]; m[2] = n; }
               if (m[1] < m[2]) { int n = m[1]; m[1] = m[2]; m[2] = n; }

               if (m[3] < m[4]) { int n = m[3]; m[3] = m[4]; m[4] = n; }
               if (m[3] < m[5]) { int n = m[3]; m[3] = m[5]; m[5] = n; }
               if (m[4] < m[5]) { int n = m[4]; m[4] = m[5]; m[5] = n; }

               int n1 = (m[0] << 18) | (m[1] << 9) | m[2];
               int n2 = (m[3] << 18) | (m[4] << 9) | m[5];

               if (band_swap && n1 < n2) { int n = n1; n1 = n2; n2 = n; }

               p_flags[find_pattern(n1, n2)] = true;

               c_order += 9;
            }
         }
      }
      // read next ED 27+?+? pattern
   }

   fprintf(stderr, "<band,pattern> count = %d\n", bp_count);
#ifdef   _MSC_VER
   fprintf(stderr, "puzzle_count = %I64d [%d-%d], %.2fm\n",
      puzzle_count, start, end - 1, (double)clock() / CLOCKS_PER_SEC / 60);
#else
   fprintf(stderr, "puzzle_count = %lld [%d-%d], %.2fm\n",
      puzzle_count, start, end - 1, (double)clock() / CLOCKS_PER_SEC / 60);
#endif

   return 0;
}

///>>>>>>>>>>>>>>>>>>>>>>>>>> code for generate patterns and sort

        int np = 0;

         int col_p[3];
         for (int stack_p = 0; stack_p < 6; stack_p++)
         for (col_p[0] = 0; col_p[0] < 6; col_p[0]++)
         for (col_p[1] = 0; col_p[1] < 6; col_p[1]++)
         for (col_p[2] = 0; col_p[2] < 6; col_p[2]++)   {
            int m[6];
            memset(m, 0, sizeof(m));
            {  int c_order[9];

               {
                  for (int i = 0; i < 3; i++)
                  for (int j = 0; j < 3; j++)
                     c_order[3 * i + j] = 3 * p3[stack_p][i] + p3[col_p[i]][j];
               }

               for (int i = 0; i < 6; i++)
               for (int j = 0; j < 9; j++)
               {
                  if (grid[27 + 9 * i + c_order[j]])
                     m[i] |= 0x100 >> j;
               }
            }

            if (m[0] < m[1]) { int n = m[0]; m[0] = m[1]; m[1] = n; }
            if (m[0] < m[2]) { int n = m[0]; m[0] = m[2]; m[2] = n; }
            if (m[1] < m[2]) { int n = m[1]; m[1] = m[2]; m[2] = n; }

            if (m[3] < m[4]) { int n = m[3]; m[3] = m[4]; m[4] = n; }
            if (m[3] < m[5]) { int n = m[3]; m[3] = m[5]; m[5] = n; }
            if (m[4] < m[5]) { int n = m[4]; m[4] = m[5]; m[5] = n; }

            int n1 = (m[0] << 18) | (m[1] << 9) | m[2];
            int n2 = (m[3] << 18) | (m[4] << 9) | m[5];

            if (band_swap && n1 < n2) { int n = n1; n1 = n2; n2 = n; }

            patterns[np][0] = n1;
            patterns[np][1] = n2;
            ++np;
         }
      }

      {
         // remove duplicates

         qsort(patterns, 1296, sizeof(patterns[0]), p_compare);
         pattern_count = 1;

         for (int np = 1; np < 1296; np++)
         {
            if (patterns[np][0] != patterns[pattern_count - 1][0]
            || patterns[np][1] != patterns[pattern_count - 1][1])
            {
               patterns[pattern_count][0] = patterns[np][0];
               patterns[pattern_count][1] = patterns[np][1];
               ++pattern_count;
            }
         }



void bp_handler(char *buf, int n44 = -1){
   // generate puzzles to be tested for input <band,pattern> case
   // assume n44 ok here searched from buf
   gangster_data &gt = gtd[n44];
   struct _grid {
      unsigned char cells[9][9];
      int boxmasks[9];
      int rowmasks[9];
      int colmasks[9];
   };
     _grid grid;
   memset(&grid, 0, sizeof(grid));

   for (int i = 0; i < 27; i++)      {
         grid.cells[i / 9][i % 9] = buf[i] - '0';
         grid.colmasks[i % 9] |= (1 << (buf[i] - '0'));
      }

   enum { MaxPatCells = 8, };
   int numbers[MaxPatCells];
   struct spot {
      int r;      int c;      int b;      int dmask;
   };
   spot spots[MaxPatCells];
   spot *s = spots;

   for (int i = 27; i < 81; i++)      {
         if (buf[i] < '0' || buf[i] > '9')       continue;

         if (s >= spots + MaxPatCells)         {
            puts("MaxPatCells exceeded");
            exit(-1);
         }
         s->r = i / 9;    s->c = i % 9;  s->b = box_table[s->r][s->c];
         ++s;
    }
   int pat_cells = (int)(s - spots);
   s = spots;
next_spot:
   int mask = grid.rowmasks[s->r]
         | grid.colmasks[s->c]
         | grid.boxmasks[s->b];
   mask = 511 & ~(mask >> 1);
   if (!mask)         goto backtrack;
   s->dmask = mask;

next_value:
	int number = first_bit[s->dmask] + 1;
    s->dmask &= (s->dmask - 1);
    numbers[s - spots] = number;
    grid.cells[s->r][s->c] = number;
    grid.rowmasks[s->r] |= (1 << number);
    grid.colmasks[s->c] |= (1 << number);
    grid.boxmasks[s->b] |= (1 << number);
    if (++s < spots + pat_cells)  goto next_spot;
    // skip puzzle if it is "gangster equivalent" (via relabeling),
    // to a puzzle that has already been checked.

    unsigned char *map = n_aut_maps[gt.first_n_aut] + 10;

    for (int n = 1; n < gt.n_aut_count; n++)      {
         for (int i = 0; i < pat_cells; i++)         {
            int d = map[numbers[i]];
            if (d < numbers[i])
               goto backtrack;
            if (d > numbers[i])
               break;
         }
         map += 10;
    }

   // TODO:: dump or test puzzle in 'grid.cells[][]'

   ++puzzle_count;
backtrack:
   if (--s < spots)      return;
   int number = grid.cells[s->r][s->c];
   grid.cells[s->r][s->c] = 0;
   grid.rowmasks[s->r] &= ~(1 << number);
   grid.colmasks[s->c] &= ~(1 << number);
   grid.boxmasks[s->b] &= ~(1 << number);
   if (!s->dmask)      goto backtrack;
   goto next_value;
}



*/